import json
import logging
from werkzeug.routing import Map, Rule, ValidationError, RequestRedirect
from flask import Flask, request, jsonify
from flask_restful import Api, Resource

app = Flask(__name__)
api = Api(app)

# 配置日志
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

# 存储接口配置（支持动态路径参数）
endpoints = {}


class DynamicEndpoint(Resource):
    def get(self, path):
        return self._process_request('GET', path)

    def post(self, path):
        return self._process_request('POST', path)

    def put(self, path):
        return self._process_request('PUT', path)

    def delete(self, path):
        return self._process_request('DELETE', path)

    def _process_request(self, method, path):
        logger.debug(f"Processing {method} request for path: {path}")

        # 匹配已配置的动态路由
        matched_config, path_params = self._match_route(method, path)

        if not matched_config:
            logger.warning(f"No route matched for {method} {path}")
            return jsonify({"error": "Endpoint not found"}), 404

        logger.debug(f"Matched config: {matched_config}")
        logger.debug(f"Path params: {path_params}")

        # 响应配置
        response_config = matched_config.get('response', {})
        status_code = matched_config.get('status_code', 200)
        headers = matched_config.get('headers', {})

        # 动态替换响应中的路径参数
        if isinstance(response_config, dict):
            response_body = self._replace_dynamic_params(response_config, path_params)
        else:
            response_body = response_config

        return jsonify(response_body), status_code, headers

    def _match_route(self, method, path):
        """匹配预配置的动态路由规则"""
        request_path = f'/{path}'  # 添加前导斜杠以适配Flask路径规则

        logger.debug(f"Matching route for: {method} {request_path}")

        for (config_method, path_rule), config in endpoints.items():
            if config_method != method:
                continue

            logger.debug(f"Trying rule: {path_rule}")

            try:
                url_map = Map([Rule(path_rule)])
                adapter = url_map.bind('dummy-server')
                path_params = adapter.match(request_path)
                logger.debug(f"Matched {path_rule} with params: {path_params}")
                return config, path_params
            except (RequestRedirect, ValidationError) as e:
                logger.debug(f"Rule {path_rule} not matched: {str(e)}")
                continue

        return None, None

    def _replace_dynamic_params(self, response_data, path_params):
        """替换响应中的动态参数占位符"""
        if isinstance(response_data, dict):
            return {k: self._replace_dynamic_params(v, path_params)
                    for k, v in response_data.items()}
        elif isinstance(response_data, list):
            return [self._replace_dynamic_params(item, path_params)
                    for item in response_data]
        elif isinstance(response_data, str) and response_data.startswith(':'):
            key = response_data[1:]
            return path_params.get(key, response_data)
        return response_data


def add_endpoint(method, path_rule, response, status_code=200, headers=None):
    """
    添加/更新动态接口配置
    :param method: HTTP方法（GET/POST等）
    :param path_rule: 支持Flask路径语法，必须以/开头，如 /api/user/<int:id>
    :param response: 响应内容（字典或字符串）
    :param status_code: HTTP状态码
    :param headers: 自定义响应头
    """
    if not path_rule.startswith('/'):
        raise ValueError("Path rule must start with '/'")

    endpoints[(method.upper(), path_rule)] = {
        'response': response,
        'status_code': status_code,
        'headers': headers or {}
    }
    logger.info(f"Endpoint added: {method} {path_rule}")


if __name__ == '__main__':
    # 示例接口配置（注意路径必须以/开头）
    add_endpoint('GET', '/api/user/<int:user_id>',
                 {'id': ':user_id', 'name': 'Test User'})

    add_endpoint('GET', '/api/product/<int:product_id>',
                 {'product_id': ':product_id', 'stock': 100})

    add_endpoint('POST', '/api/login',
                 {'token': 'abcd1234'},
                 status_code=201,
                 headers={'X-Custom-Header': 'auth'})

    # 启动服务
    app.run(host='0.0.0.0', port=5000, debug=True)